import { ImageItem } from './imageitem';
import { EventBase } from '../eventbase';
import { Rect } from '../geometry/rect';
import { HorizontalAlign, VerticalAlign, StretchDirection } from './enums';
import { EventNames } from './eventnames';
import { Size } from '../geometry/size';

export class ImageRender extends EventBase {

    //#region 字段定义
    /**最大图片宽度 */
    private _maxImageWidth: number = 0;
    /**最大图片高度 */
    private _maxImageHeight: number = 0;
    /**当前画板底图图片url集合 */
    private _imageUrls: string[];
    /**当前加载成功的图片元素集合 */
    private _images: ImageItem[] = [];
    /**当前加载失败的图片元素集合 */
    private _errorImages: ImageItem[] = [];
    /**底图图片x方向缩放比例 */
    private _imageScaleX: number = 1;
    /**底图图片y方向缩放比例 */
    private _imageScaleY: number = 1;
    /**所有底图图片的最终呈现区域 */
    private _imageRect: Rect = Rect.Empty;
    /**底图或html内容水平对齐方式 */
    private  _horizontalAlign = HorizontalAlign.Left;
    /**底图或html内容垂直对齐方式 */
    private _verticalAlign = VerticalAlign.Top;
    /**是否自动处理图片拉伸 */
    private _autoStrech: boolean = true;
    /**图片自定义拉伸方向(autoStrech)为false时此设置有效
     * ,如果设置的图片为多张则设置为StretchDirection.Height不会起作用
     * ,如果设置的图片为多张verticalAlign设置也将不会起作用,只允许顶对齐
     */
    private _stretchDirection = StretchDirection.None;
    /**获取渲染图片的可见高宽度 */
    private _getRenderBounds: () => Rect;
    /**
     * 获取上次呈现内容时的区域大小
     */
    private _lastRenderLimitSize: Size = Size.Empty;
    //#endregion

    //#region 构造函数
    /**
     * 构造函数
     * @param getRenderBounds 
     * @param horizontalAlign 
     * @param verticalAlign 
     * @param autoStrech 
     * @param stretchDirection 
     */
    constructor(getRenderBounds: () => Rect, horizontalAlign: HorizontalAlign, 
    verticalAlign: VerticalAlign, autoStrech: boolean, stretchDirection: StretchDirection) {
        super();
        this._getRenderBounds = getRenderBounds;
        this._horizontalAlign = horizontalAlign;
        this._verticalAlign = verticalAlign;
        this._autoStrech = autoStrech;
        this._stretchDirection = stretchDirection;
    }
    //#endregion

    //#region 属性定义
    /**获取或设置图片集合 */
    public get imageUrls() {
        return this._imageUrls;
    }
    public set imageUrls(value: string[]) {
        if (this._imageUrls !== value) {
            this._imageUrls = value;

        }
    }
    /**获取生成的图片标签集合 */
    public get images() {
        return this._images;
    }
    /**获取生成错误的图片标签集合 */
    public get errorImages() {
        return this._errorImages;
    }
    /**获取是否仅存在一张加载成功的图片 */
    public get isSingleImage() {
        return this._images && this._images.length === 1;
    }
    /**获取是否存在多张加载成功的图片 */
    public get isMutipleImage() {
        return this._images && this._images.length > 1;
    }
    /**获取是否存在加载成功的图片 */
    public get existImage() {
        return this._images && this._images.length > 0;
    }
    /**获取是否存在加载错误的图片 */
    public get existErrorImage() {
        return this._errorImages && this._errorImages.length > 0;
    }
    /**获取或设置底图或html内容水平对齐方式 */
    public get horizontalAlign() {
        return this._horizontalAlign;
    }
    public set horizontalAlign(value: HorizontalAlign) {
        if (value !== this._horizontalAlign) {
            this._horizontalAlign = value;
        }   
    }
    /**获取或设置底图或html内容垂直对齐方式 */
    public get verticalAlign() {
        return this._verticalAlign;
    }
    public set verticalAlign(value: VerticalAlign) {
        if (value !== this._verticalAlign) {
            this._verticalAlign = value;
        }   
    }
    /**获取或设置是否自动处理图片拉伸 */
    public get autoStrech() {
        return this._autoStrech;
    }
    public set autoStrech(value: boolean) {
        if (value !== this._autoStrech) {
            this._autoStrech = value;
        }   
    }
    /**获取或设置图片自定义拉伸方向(autoStrech)为false时此设置有效
     * ,如果设置的图片为多张则设置为StretchDirection.Height不会起作用
     * ,如果设置的图片为多张verticalAlign设置也将不会起作用,只允许顶对齐
     */
    public get stretchDirection() {
        return this._stretchDirection;
    }
    public set stretchDirection(value: StretchDirection) {
        if (value !== this._stretchDirection) {
            this._stretchDirection = value;
        }   
    }
    /**获取底图图片x方向缩放比例 */
    public get imageScaleX() {
        return this._imageScaleX;
    }
    /**获取底图图片y方向缩放比例 */
    public get imageScaleY() {
        return this._imageScaleY;
    }
    /**
     * 获取所有图片的呈现区域
     */
    public get bounds() {
        return this._imageRect;
    }
    //#endregion

    //#region 公共方法
    /**
     * 渲染图片
     * @param ctx 
     */
    public render(ctx: CanvasRenderingContext2D) {
        if (ctx) {
            const images = this._images;
            if (images && images.length > 0) {
                images.forEach((item) => {
                    if (!item.isError && item.image && !item.bounds.isEmpty()) {
                        const rect = item.bounds;
                        ctx.drawImage(item.image, rect.x, rect.y, rect.width, rect.height);
                    }
                });
            }
        }
    }
    /**
     * 异步加载图片
     * @param callback 加载完成回调方法
     */
    public loadImagesAsync(callback: (images: ImageItem[], errorImages: ImageItem[]) => void) {
        this._imageScaleX = 1;
        this._imageScaleY = 1;
        const _callback = (images: ImageItem[], errorImages: ImageItem[]) => {
            this._images = images || [];
            this._errorImages = errorImages || [];
            // 刷新所有图片的最终呈现区域
            this.caculateImagesRenderBounds();
            if (callback) {
                callback(images, errorImages);
            }
        };
        if (this.imageUrls && this.imageUrls.length > 0) {
            const images: ImageItem[] = [];
            const imageWidthArray: number[] = [];
            const imageHeigthArray: number[] = [];

            // 异步加载各图片
            this.imageUrls.forEach((url, index) => {
                const imageItem = new ImageItem(url, index);
                imageItem.loadImageAsync((item) => {
                    images.push(item);
                    if (!item.isError) {
                        imageWidthArray.push(item.width);
                        imageHeigthArray.push(item.height);
                    }
                });
            });
            let loadInterval = 0;
            const chkLoadFinished = () => {
                if (images.length === this.imageUrls.length) {
                    // 停止检查计时器
                    window.clearInterval(loadInterval);
                    // 设置最大图片宽度和高度
                    this._maxImageWidth = Math.max(...imageWidthArray);
                    this._maxImageHeight = Math.max(...imageHeigthArray);
                    // 处理加载之后的图片
                    this.filterAndProcessImage(images, this._maxImageWidth, this._maxImageHeight, _callback);
                }
            };
            // 创建检查计时器
            loadInterval = window.setInterval(chkLoadFinished, 300);
        } else {
            _callback([], []);
        }
    }
    /**
     * 根据当前有效呈现区域来重新刷新图片呈现区域
     */
    public refreshImagesRenderBounds(callback?: (bounds: Rect) => void) {
        if (this._images && this._images.length > 0) {
            // 设置各图片呈现区域
            this.setImageRenderBounds(this._images, this._maxImageWidth, this._maxImageHeight);
        }
        // 刷新所有图片的最终呈现区域
        this.caculateImagesRenderBounds();
        // 回调处理
        if (callback) {
            callback(this._imageRect);
        }
    }
    /**
     * 旋转图片
     * @param imgIndex 
     * @param angle 
     * @param callback
     */
    public imageRotate(imgIndex = 0, angle: number, callback?: () => void) {
        if (this.images && this.images.length > 0 && imgIndex >= 0 && imgIndex < this.images.length) {
            this.images[imgIndex].imageRotate(angle, callback);
        }
    }
    /**
     * 提高图片亮度
     * @param imgIndex 
     * @param callback
     */
    public brightLightUp(imgIndex = 0, callback?: () => void) {
        if (this.images && this.images.length > 0 && imgIndex >= 0 && imgIndex < this.images.length) {
            this.images[imgIndex].brightLightUp(callback);
        }
    }
    /**
     * 降低图片亮度
     * @param imgIndex 
     * @param callback
     */
    public brightLightDown(imgIndex = 0, callback?: () => void) {
        if (this.images && this.images.length > 0 && imgIndex >= 0 && imgIndex < this.images.length) {
            this.images[imgIndex].brightLightDown(callback);
        }
    }
    /**
     * 缩小图片
     * @param imgIndex 
     * @param callback
     */
    public imageScaleIn(imgIndex = 0, callback?: (deltWidth: number, deltHeight: number, relateScale: number) => void) {
        if (this.images && this.images.length > 0 && imgIndex >= 0 && imgIndex < this.images.length) {
            this.scaleImage(this.images[imgIndex], imgIndex, true, callback);
        }
    }
    /**
     * 放大图片
     * @param imgIndex 
     * @param callback
     */
    public imageScaleOut(imgIndex = 0, callback?: (deltWidth: number, deltHeight: number, relateScale: number) => void) {
        if (this.images && this.images.length > 0 && imgIndex >= 0 && imgIndex < this.images.length) {
            this.scaleImage(this.images[imgIndex], imgIndex, false, callback);
        }
    }

    //#endregion

    //#region 私有方法
    /**
     * 处理并过滤加载之后的图片
     * @param images 待处理的图片
     * @param maxWidth 待处理的图片的最大宽度
     * @param maxHeight 待处理的图片的最大高度
     * @param callback 处理完成回调处理
     */
    private filterAndProcessImage(images: ImageItem[], maxWidth: number, maxHeight: number, callback: (images: ImageItem[], errorImages: ImageItem[]) => void) {
        const _callback = (images: ImageItem[], errorImages: ImageItem[]) => {
            if (callback) {
                callback(images, errorImages);
            }
        };
        if (images && images.length > 0) {
            // 过滤加载失败的图片
            images = images.filter((img) => !img.isError);
            // 排序
            const srotExpression = (a: ImageItem, b: ImageItem) => {
                const num1 = a ? a.order : -1;
                const num2 = b ? b.order : -1;
                return num1 - num2;
            };
            images = images.sort(srotExpression);
            //设置图片集合
            let errorImages = images.filter((img) => img.isError);
            errorImages = errorImages.sort(srotExpression);
            //设置图像呈现区域
            this.setImageRenderBounds(images, maxWidth, maxHeight);
            // 回调处理
            _callback(images, errorImages);
        } else {
            _callback([], []);
        }
    }
    /**
     * 设置图片呈现区域
     * @param images 
     * @param _maxWidth 待处理的图片的最大宽度
     * @param _maxHeight 待处理的图片的最大高度
     */
    private setImageRenderBounds(images: ImageItem[], _maxWidth: number, _maxHeight: number) {
        const renderBounds = this._getRenderBounds ? this._getRenderBounds() : Rect.Empty;
        this._lastRenderLimitSize = new Size(renderBounds.width, renderBounds.height);
        const disWidth = renderBounds.width;
        const disHeight = renderBounds.height;
        let setRenderRect = (_curImage: ImageItem, _lastImageRenderEndY: number) => {
        };
        
        // 设置图片拉伸方向
        let strechDirection = StretchDirection.None;
        if (this.autoStrech) {
            if (images.length === 1) {
                strechDirection = StretchDirection.None;
            }
        } else {
            strechDirection = this.stretchDirection;
        }
        // 设置获取图片渲染区域的处理
        if (images.length === 1) {
            setRenderRect = (_curImage: ImageItem, _lastImageRenderEndY: number) => {
                let renderX = 0, renderY = 0, renderWidth = 0, renderHeight = 0;
                if (strechDirection === StretchDirection.None || strechDirection === StretchDirection.Width) {
                    //#region StretchDirection.None 和 StretchDirection.Width 渲染宽高度计算
                    if (strechDirection === StretchDirection.None) {
                        renderWidth = Math.min(_curImage.width, disWidth);
                    } else if (strechDirection === StretchDirection.Width) {
                        renderWidth = disWidth;
                    }
                    renderHeight = renderWidth / _curImage.level;
                    if (renderHeight > disHeight) {
                        renderHeight = disHeight;
                        renderWidth = renderHeight * _curImage.level;
                    }
                    //#endregion
                } else {
                    //#region StretchDirection.Height 渲染宽、高度计算
                    renderHeight = disHeight;
                    renderWidth = renderHeight * _curImage.level;
                    if (renderWidth > disWidth) {
                        renderWidth = disWidth;
                        renderHeight = renderWidth / _curImage.level;
                    }
                    //#endregion
                }
                // 计算渲染的起始x坐标
                if (this.horizontalAlign === HorizontalAlign.Center) {
                    renderX = (disWidth - renderWidth) / 2;
                } else if (this.horizontalAlign === HorizontalAlign.Right) {
                    renderX = disWidth - renderWidth;
                }
                if (this.verticalAlign === VerticalAlign.Middle) {
                    renderY = (disHeight - renderHeight) / 2;
                } else if (this.verticalAlign === VerticalAlign.Bottom) {
                    renderY = disHeight - renderHeight;
                }
                _curImage.bounds = new Rect(renderX, renderY, renderWidth, renderHeight); 
            };
        } else if (images.length > 1) {
            setRenderRect = (_curImage: ImageItem, _lastImageRenderEndY: number) => {
                let renderX = 0, renderY = 0, renderWidth = 0, renderHeight = 0;
                // 计算图片渲染宽度仅适配拉伸宽度或不拉伸
                if (strechDirection === StretchDirection.Width) {
                    renderWidth = disWidth;
                } else {
                    renderWidth = Math.min(_curImage.width, disWidth);
                } 
                // 允许图片在保持宽高比下延申高度(将导致显示滚动条)
                renderHeight = renderWidth / _curImage.level;
                _curImage.bounds = new Rect(renderX, renderY, renderWidth, renderHeight); 
                if (this.horizontalAlign === HorizontalAlign.Center) {
                    renderX = (disWidth - renderWidth) / 2;
                } else if (this.horizontalAlign === HorizontalAlign.Right) {
                    renderX = disWidth - renderWidth;
                }
                // 多张图片时垂直方向将强制顶对齐
                renderY += _lastImageRenderEndY;
                _curImage.bounds = new Rect(renderX, renderY, renderWidth, renderHeight); 
            };
        }
        
        let lastImageRenderEndY = 0, actualImageTotalWidth = 0, actualImageTotalHeight = 0,
        imageRenderTotalWidth = 0, imageRenderTotalHeight = 0;

        images.forEach((image) => {
            setRenderRect(image, lastImageRenderEndY);
            lastImageRenderEndY += image.bounds.height;
            actualImageTotalWidth = Math.max(actualImageTotalWidth, image.width);
            actualImageTotalHeight += image.height;
            imageRenderTotalWidth = Math.max(imageRenderTotalWidth, image.bounds.width);
            imageRenderTotalHeight += image.bounds.height;
        });
        this._imageScaleX = imageRenderTotalWidth / actualImageTotalWidth;
        this._imageScaleY = imageRenderTotalHeight / actualImageTotalHeight;
    }
    /**
     * 计算所有图片的最终呈现区域
     */
    private caculateImagesRenderBounds() {
        let rect = Rect.Empty;
        if (this._images && this._images.length) {
            this._images.forEach((imageItem) => {
                const strokeRect = imageItem.bounds;
                rect = rect.union(strokeRect);
            });
        }
        this._imageRect = rect;
    }
    /**
     * 放大或缩小图片
     * @param image 对应的图片实例
     * @param imgIndex 对应图片实例的索引
     * @param scaleIn 标识是否为缩小操作
     * @param callback 回调处理
     */
    private scaleImage(image: ImageItem, imgIndex: number, scaleIn = true, callback?: (deltWidth: number, deltHeight: number, ralteScale: number) => void) {
        if (!image) return;
        let ralteScale = 1;
        if (scaleIn) {
            ralteScale = image.scaleIn();
        } else {
            ralteScale = image.scaleOut();
        }
        if (ralteScale === 1) {
            return;
        }
        let newX = 0, newY = 0, newWidth = 0, newHeight = 0;
            const curBounds = image.bounds;
            // 图片新的渲染宽、高度
            newWidth = curBounds.width * ralteScale;
            newHeight = curBounds.height * ralteScale;
            // 图片渲染宽、高度变换值
            const deltWidth = newWidth - curBounds.width;
            const deltHeight = newHeight - curBounds.height;
            // 计算进行缩放处理的图片新的x坐标
            if (this.horizontalAlign === HorizontalAlign.Left) {
                newX = curBounds.x;
            } else if (this.horizontalAlign === HorizontalAlign.Center) {
                newX = curBounds.x - deltWidth / 2;
            } else if (this.horizontalAlign === HorizontalAlign.Right) {
                newX = curBounds.x - deltWidth;
            }
            // 计算进行缩放处理的图片新的y坐标
            if (this.images.length === 1) {
                // 单张图片处理
                if (this.verticalAlign === VerticalAlign.Top) {
                    newY = curBounds.y;
                } else if (this.verticalAlign === VerticalAlign.Middle) {
                    newY = curBounds.y - deltHeight / 2;
                } else if (this.verticalAlign === VerticalAlign.Bottom) {
                    newY = curBounds.y - deltHeight;
                }
            } else {
                // 多张图片
                if (this.verticalAlign === VerticalAlign.Top) {
                    newY = curBounds.y;
                } else {
                    if (imgIndex === 0) {
                        newY = 0;
                    } else {
                        const lastImageBounds = this.images[imgIndex - 1].bounds;
                        newY = lastImageBounds.y + lastImageBounds.height;
                    }
                }
            }
            // 图片新的渲染范围
            image.bounds = new Rect(newX, newY, newWidth, newHeight);
            if (this.images.length > 1) {
                // 更新其他图片的渲染区域
                let startY = newY + newHeight;
                for (let index = imgIndex + 1; index < this.images.length; index++) {
                    const item = this.images[index];
                    item.bounds.y = startY;
                    startY += item.bounds.height;
                }
            }

            //计算单张图片的缩放比例
            if (this._images.length === 1) {
                const image = this._images[0];
                this._imageScaleX = image.bounds.width / image.width;
                this._imageScaleY = image.bounds.height / image.height;
            }

            // 刷新所有图片最终呈现区域
            this.caculateImagesRenderBounds();

            // 回调处理
            if (callback) {
                callback(deltWidth, deltHeight, ralteScale);
            }
    }
    //#endregion
}